﻿
Imports std
Imports centrosphere.sharedMemory

Namespace sharedMemory
    Public Module _sharedMemory
        Private _shared_host As String = Nothing
        Private _shared_port As Int32 = 0

        Public Property shared_host() As String
            Get
                Return _shared_host
            End Get
            Set(value As String)
                copy(_shared_host, value)
            End Set
        End Property

        Public Property shared_port() As Int32
            Get
                Return _shared_port
            End Get
            Set(value As Int32)
                copy(_shared_port, value)
            End Set
        End Property
    End Module
End Namespace

Public Class sharedMemory(Of T, T2 As {bytesbase(Of T), New})
    Private Shared ReadOnly updateIntervalMs As Int64 = 500
    Private Shared ReadOnly defaultT2 As T2 = [default](Of T2)()
    Private ReadOnly v As T2 = Nothing
    Private ReadOnly _name As String = Nothing
    Private ReadOnly _host As String = Nothing
    Private ReadOnly _port As Int32 = 0
    Private ReadOnly emitter As storageJobRcEmitter = Nothing

    Public Shared WriteOnly Property shared_address() As String
        Set(value As String)
            assert(parseHostPort(value, shared_host(), shared_port()))
        End Set
    End Property

    Public Sub New(ByVal host As String, ByVal port As Int32, ByVal name As String, ByVal v As T2)
        assert(Not isemptystring(host))
        assert(port > 0)
        assert(Not isemptystring(name))
        If v Is Nothing Then
            v = New T2()
        End If

        copy(_host, host)
        copy(_port, port)
        copy(_name, name)
        copy(Me.v, v)
        emitter = New storageJobRcEmitter(Me.host(), Me.port())
        write(v)
        read()
    End Sub

    Public Sub New(ByVal host As String, ByVal port As Int32, ByVal name As String, ByVal v As T)
        Me.New(host, port, name, New T2() With {.value = v})
    End Sub

    Public Sub New(ByVal host As String, ByVal port As Int32, ByVal name As String)
        Me.New(host, port, name, defaultT2)
    End Sub

    Public Sub New(ByVal address As pair(Of String, Int32), ByVal name As String, ByVal v As T2)
        Me.New(address.first, address.second, name, v)
    End Sub

    Public Sub New(ByVal address As pair(Of String, Int32), ByVal name As String, ByVal v As T)
        Me.New(address, name, New T2() With {.value = v})
    End Sub

    Public Sub New(ByVal address As pair(Of String, Int32), ByVal name As String)
        Me.New(address, name, defaultT2)
    End Sub

    Private Shared Function parse_host_port(ByVal address As String) As pair(Of String, Int32)
        Dim host As String = Nothing
        Dim port As Int32 = 0
        assert(parseHostPort(address, host, port))
        Return make_pair(host, port)
    End Function

    Public Sub New(ByVal address As String, ByVal name As String, ByVal v As T2)
        Me.New(parse_host_port(address), name, v)
    End Sub

    Public Sub New(ByVal address As String, ByVal name As String, ByVal v As T)
        Me.New(address, name, New T2() With {.value = v})
    End Sub

    Public Sub New(ByVal address As String, ByVal name As String)
        Me.New(address, name, defaultT2)
    End Sub

    Public Sub New(ByVal name As String, ByVal v As T2)
        Me.New(shared_host(), shared_port(), name, v)
    End Sub

    Public Sub New(ByVal name As String, ByVal v As T)
        Me.New(name, New T2() With {.value = v})
    End Sub

    Public Sub New(ByVal name As String)
        Me.New(name, defaultT2)
    End Sub

    Public Function host() As String
        Return _host
    End Function

    Public Function port() As String
        Return _port
    End Function

    Public Function name() As String
        Return _name
    End Function

    Public Function value() As T
        Return +v
    End Function

    Public Shared Operator +(ByVal this As sharedMemory(Of T, T2)) As T
        If this Is Nothing Then
            Return Nothing
        Else
            Return this.value()
        End If
    End Operator

    Public Function write(ByVal v As T2) As Boolean
        If v Is Nothing Then
            Return False
        Else
            Dim ec As eventComb = Nothing
            If emitter.modify(name, v.tobytes(), Nothing, ec) Then
                Return begin(ec)
            Else
                raiseError(errorHandle.errorType.warning, "cannot run emitter.modify")
                Return False
            End If
        End If
    End Function

    Public Function write(ByVal v As T) As Boolean
        Dim a As T2 = New T2()
        a.attach(v)
        Return write(a)
    End Function

    Private Sub read()
        Dim ec As eventComb = Nothing
        Dim buff As pointer(Of bytes) = Nothing
        buff = New pointer(Of bytes)()
        assert_begin(New eventComb(Function() As Boolean
                                       buff.clear()
                                       ec = Nothing
                                       Return emitter.read(name, buff, Nothing, ec) AndAlso
                                              waitfor(ec) AndAlso
                                              goto_next()
                                   End Function,
                                   Function() As Boolean
                                       If ec.end_result() Then
                                           If buff Is Nothing Then
                                               raiseError(errorHandle.errorType.warning,
                                                          "buff is nothing when ec.end_result()")
                                           Else
                                               v.frombytes(+buff)
                                           End If
                                       End If
                                       Return waitfor(updateIntervalMs) AndAlso
                                              goto_prev()
                                   End Function))
    End Sub
End Class
